/*
 * Object.h
 *
 *  Created on: 2011-7-8
 *      Author: gexiao
 */
/*
 * Declaration of the fundamental Object type and refinements thereof,plus
 * some functions for manipulating them.
 */
#ifndef OBJECT_H_
#define OBJECT_H_

#include "../Common.h"
#include "../Sync.h"
#include "../../libdex/DexProto.h"
#include "../DvmDex.h"
#include <stddef.h>

/*
 * fwd decl
 */
struct DataObject;
struct InitiatingLoaderList;
struct ClassObject;
struct StringObject;
struct ArrayObject;
struct Method;
//some code here
struct StaticField;
struct InstField;
struct Field;
struct RegisterMap;
typedef struct DataObject DataObject;
typedef struct InitiatingLoaderList InitiatingLoaderList;
typedef struct ClassObject ClassObject;
typedef struct StringObject StringObject;
typedef struct ArrayObject ArrayObject;
typedef struct Method Method;
//some code
typedef struct StaticField StaticField;
typedef struct InstField InstField;
typedef struct Field Field;
typedef struct RegisterMap RegisterMap;

/*
 * Native function pointer type.
 *
 * "args[0]" holds the "this" pointer for virtual methods.
 *
 * The "Bridge" form is a super-set of the "Native" form; in many places
 * they are used interchangeably. Currently, all functions have all
 * arguments passed in, but some functions only care about the first two.
 * Passing extra arguments to a C function is (mostly) harmless.
 */
typedef void (*DalvikBridgeFunc)(const u4* args, JValue* pResult,
		const Method* method, struct Thread* self);
typedef void (*DalvikNativeFunc)(const u4* args, JValue* pResult);

//vm-internal access flags and related definitions
typedef enum AccessFlags {
	ACC_MIRANDA = 0x8000,//method(internal to VM)
	JAVA_FLAGS_MASK = 0xffff,
//bits set from Java sources (low 16)
} AccessFlags;

/*
 * Use the top 16 bits of the access flags field for
 * other class flags. Code should use the *CLASS_FLAG*()
 * macros to set/get these flags.
 */
typedef enum ClassFlags {
	CLASS_ISFINALIZABLE = (1 << 31),// class/ancestor overrides finalize()
	CLASS_ISARRAY = (1 << 30),//class is a "[*"
	CLASS_ISOBJECTARRAY = (1 << 29),//class is a "[L*" or "[[*"
	CLASS_ISREFERENCE = (1 << 28),//class is a soft/weak/phantom ref
	//only ISREFERENCE is set --> soft
	CLASS_ISWEAKREFERENCE = (1 << 27),//class is a weak reference
	CLASS_ISPHANTOMREFERENCE = (1 << 26),//class is a phantom reference

	CLASS_MULTIPLE_DEFS = (1 << 25),//DEX verifier: defs in multiple DEXs

	//unlike the others, these can be present in the optimized DEX file
	CLASS_ISOPTIMIZED = (1 << 17),//class may contain opt instrs
	CLASS_ISPREVERIFIED = (1 << 16),
//class has been pre-verified
} ClassFlags;

//current state of the class, increasing as we progress
typedef enum ClassStatus {
	CLASS_ERROR = -1,

	CLASS_NOTREADY = 0, CLASS_IDX = 1, /* loaded, DEX idx in super or ifaces */
	CLASS_LOADED = 2, /* DEX idx values resolved */
	CLASS_RESOLVED = 3, /* part of linking */
	CLASS_VERIFYING = 4, /* in the process of being verified */
	CLASS_VERIFIED = 5, /* logically part of linking; done pre-init */
	CLASS_INITIALIZING = 6, /* class init in progress */
	CLASS_INITIALIZED = 7,
/* ready to go */
} ClassStatus;

/*
 * Primitive type identifiers. We use these values as indexes into an
 * array of synthesized classes, so these start at zero and count up.
 * The order is arbitrary (mimics table in doc for newarray opcode),
 * but can't be changed without shuffling some reflection tables.
 *
 * PROM_VOID can't be used as an array type,but we include it here for
 * other uses (e.g. Void.TYPE).
 */
typedef enum PrimitiveType {
	PRIM_NOT = -1,//value is not a primitive type
	PRIM_BOOLEAN = 0,
	PRIM_CHAR = 1,
	PRIM_FLOAT = 2,
	PRIM_DOUBLE = 3,
	PRIM_BYTE = 4,
	PRIM_SHORT = 5,
	PRIM_INT = 6,
	PRIM_LONG = 7,
	PRIM_VOID = 8,
	PRIM_MAX
} PrimitiveType;

/*
 * This defines the amount of space we leave for field slots in the
 * java.lang.Class definition. If we alter the class to have more than
 * this many fields, the VM will abort at startup.
 */
#define CLASS_FIELD_SLOTS 4

/*
 * Used for iftable in ClassObject
 */
typedef struct InterfaceEntry {
	//pointer to interface class
	ClassObject* clazz;

	/*
	 * Index into array of vtable offsets. This points into the ifviPool,
	 * which holds the vtables for all interfaces declared by this class.
	 */
	int* methodIndexArray;
} InterfaceEntry;

/*
 * There are three types of objects:
 * 	Class objects - an instance of java.lang.Class
 * 	Array objects - an object created with a "new array" instruction
 * 	Data objects - an object that is neither of the above
 *
 * We also define String objects. At present they're equivalent to
 * DataObject,but that may change.(Either way, they make some of the
 * code more obvious.)
 *
 * All objects have an Object header followed by type-specific data.
 */
typedef struct Object {
	//ptr to class object
	ClassObject* clazz;

	/*
	 * A word containing either a "thin" lock or a "fat" monitor. See
	 * the comments in Sync.c for a description of its latout.
	 */
	u4 lock;
} Object;

/*
 * Properly initialize an Object.
 * void DVM_OBJECT_INIT(Object *obj, ClassObject *clazz_)
 */
#define DVM_OBJECT_INIT(obj, clazz_)                                    \
    do {                                                                \
        dvmSetFieldObject((Object *)obj, offsetof(Object, clazz),       \
                          (Object *)clazz_);                            \
        DVM_LOCK_INIT(&(obj)->lock);                                    \
    } while (0)

/*
 * Get/set class flags.
 */
#define SET_CLASS_FLAG(clazz,flag)\
		do {(clazz)->accessFlags|=(flag);} while(0)

#define CLEAR_CLASS_FLAG(clazz,flag)\
	do { (clazz)->accessFlags &=~(flag);} while(0)

#define IS_CLASS_FLAG_SET(clazz,flag) \
	(((clazz)->accessFlags&(flag))!=0)
#define GET_CLASS_FLAG_GROUP(clazz,flag) \
	((u4)((clazz)->accessFlags&(flag)))

/*
 * Data objects have an Object header followed by their instance data.
 */
struct DataObject {
	Object obj;//Must be first item

	//variable #of u4 slots;u8 uses 2 slots
	u4 instanceData[1];
};

/*
 * Strings are used frequently enough that we may want to give them their
 * own unique type.
 *
 * Using a dedicated type object to access the instance data provides a
 * performance advantage but makes the java/lang/String.java implementation
 * fragile.
 *
 * Currently this is just equal to DataObject, and we pull the fields out
 * like we do for any other object.
 */
struct StringObject {
	Object obj;//MUST be first item

	//variable #of u4 slots; u8 uses 2 slots
	u4 instanceData[1];
};

/*
 * Array objects have these additional fields.
 *
 * We don't currently store the size of each element. Usually it's implied
 * by the instruction. If necessary, the width can be derived from
 * the first char of obj->clazz->name.
 */
struct ArrayObject {
	Object obj; //Must be first item

	//number of elements; immutable after init
	u4 length;

	/*
	 * Array contents; actual size is (length*sizeof(type)). This is
	 * declared as u8 so that the compiler inserts any necessary padding
	 * (e.g. for EABI); the actual allocation may be smaller than 8 bytes.
	 */
	u8 contents[1];
};

/*
 * For classes created early and thus probably in the zygote, the
 * InitiatingLoaderList is kept in gDvm. Later classes use the structure in
 * Object Class. This helps keep zygote pages shared.
 */
struct InitiatingLoaderList {
	/* a list of initiating loader Objects; grown and initialized on demand */
	Object** initiatingLoaders;
	/* count of loaders in the above list */
	int initiatingLoaderCount;
};

/*
 * Class objects have many additional fields. This is used for both
 * classes and interfaces, including synthesized classes (arrays and
 * primitive types).
 *
 * Class objects are unusual in that they have some fields allocated with
 * the system malloc (or LinearAlloc), rather than on the GC heap. This is
 * handy during initialization, but does require special handling when discarding
 * java.lang.Class objects.
 *
 * The separation if methods (direct vs. virtual) and fields (class vs.
 * instance) used in Dalvik works out pretty well. The only time it's
 * annoying is when enumerating or searching for things with reflection.
 */
struct ClassObject {
	Object obj; //Must be first item

	/*
	 * leave space for instance data; we could access fields directly if we
	 * freeze the definition of java/lang/Class
	 */
	u4 instanceData[CLASS_FIELD_SLOTS];

	/*
	 * UTF-8 descriptor for the class; from constant pool, or on
	 * heap if generated("[C")
	 */
	const char* descriptor;
	char* descriptorAlloc;

	//access flags;low 16 bits are defined by VM spec
	u4 accessFlags;

	// VM-unique class serial number, nonzero, set very early
	u4 serialNumber;

	/*
	 * DexFile from which we came; needed to resolve constant pool entries
	 * (will be NULL for VM-generated, e.g. arrays and primitive classes)
	 */
	DvmDex* pDvmDex;

	//state of class initialization
	ClassStatus status;

	//if class verify fails, we must return same error on subsequent tries
	ClassObject* verifyErrorClass;

	//threadId, used to check for recursive <clinit> invocation
	u4 initThreadId;

	/*
	 * Total object size; used when allocating storage on gc heap. (For
	 * interfaces and abstract classes this will be zero.)
	 */
	size_t objectSize;

	/*
	 * array only: class object for base element, for instanceof/checkcast
	 * (for String[][][],this will be String)
	 */
	ClassObject* elementClass;

	//arrays only: number of dimensions, e.g. int[][] is 2
	int arrayDim;

	//primitive type index, or PRIM_NOT(-1); set for generated prim classes
	PrimitiveType primitiveType;

	//superclass, or NULL if this is java.lang.Object
	ClassObject* super;

	//defining class loader,or NULL for the "bootstrap" system loader
	Object* classLoader;

	/* initiating class loader list */
	/* NOTE: for classes with low serialNumber, these are unused, and the
	 values are kept in a table in gDvm. */
	InitiatingLoaderList initiatingLoaderList;

	//array of interfaces this class implements directly
	int interfaceCount;
	ClassObject** interfaces;

	//static, private,and <init> methods
	int directMethodCount;
	Method* directMethods;

	//virtual methods defined in this class; invoked through vtable
	int virtualMethodCount;
	Method* virtualMethods;

	/*
	 * Virtual method table (vtable), for use by "invoke-virtual". The
	 * vtable from superclass is copied in, and virtual methods from
	 * our class either replace those from the super or are appended.
	 */
	int vtableCount;
	Method** vtable;

	/*
	 * Interface table (iftable), one entry per interface supported by
	 * this class. That means one entry for each interface we support
	 * directly, indirectly via superclass,or indirectly via
	 * superinterface. This will be null if neither we nor our superclass
	 * implement any interfaces.
	 *
	 * Why we need this: given "class Foo implements Face", declare
	 * "Face faceObj=new Foo()". Invoke faceObj.blah(), where "blah" is
	 * part of the Face interface. We can't easily use a single vtable.
	 *
	 * For every interface a concrete class implements, we create a list of
	 * virtualMethod indices for the methods in the interface.
	 */
	int iftableCount;
	InterfaceEntry* iftable;

	/*
	 * The interface vtable indices for iftable get stored here. By placing
	 * them all in a single pool for each class that implements interfaces,
	 * we decrease the number of allocations.
	 */
	int ifviPoolCount;
	int* ifviPool;

	/*
	 * instance fields
	 *
	 * These describe the layout of the contents of a DataObject-compatible
	 * Object. Note that only the fields directly defined by this class
	 * are listed in ifields; ...
	 */
	int ifieldCount;
	int ifieldRefCount;
	InstField* ifields;

	// bitmap of offsets of ifields
	u4 refOffsets;

	//source file name, if known
	const char* sourceFile;

	//static fields
	int sfieldCount;
	StaticField* sfields;
};

/*
 * A method. We create one of these for every method in every class
 * we load, so try to keep the size to a minimum.
 *
 * Much of this comes from and could be accessed in the data held in shared
 * memory. We hold it all together here for speed. Everything but the
 * pointers could be held in a shared table generated by the optimizer;
 * if we're willing to convert them to offsets and take the performance
 * hit(e.g. "meth->insns" becomes "baseAddr + meth->insnsOffset") we
 * could move everything but "nativeFunc".
 */
struct Method {
	// the class we are a part of
	ClassObject* clazz;

	//access flags; low 16 bits are defined by spec (could be u2?)
	u4 accessFlags;

	/*
	 * For concrete virtual methods, this is the offset of the method
	 * in "vtable".
	 *
	 * For abstract methods in an interface class, this is the offset
	 * of the method in "iftable[n]->methodIndexArray".
	 */
	u2 methodIndex;

	/*
	 * Method bounds; not needed for an abstract method.
	 *
	 * For a native method, we compute the size of the argument list, and
	 * set "insSize" and "registerSize" equal to it.
	 */
	u2 registersSize;//ins+locals
	u2 outsSize;
	u2 insSize;

	//method name, e.g. "<init>" or "eatLunch"
	const char* name;

	/*
	 * Method prototype descriptor string (return and argument types).
	 *
	 * TODO: This currently must specify the DexFile as well as the proto_ids
	 * index, because generated Proxy classes don't have a DexFile. We can
	 * remove the DexFile* and reduce the size of this struct if we generate
	 * a DEX for proxies.
	 */
	DexProto prototype;

	//short-form method descriptor string
	const char* shorty;

	/*
	 * The remaining items are not used for abstract or native methods.
	 * (JNI is currently hijacking "insns" as a function pointer, set
	 * after the first call. For internal-native this stays null.)
	 */

	//the actual code
	const u2* insns;//instructions, in memory-mapped .dex

	//cached JNI argument and return-type hints
	int jniArgInfo;

	/*
	 * Native method ptr; could be actual function or a JNI bridge. We
	 * don't currently discriminate between DalvikBridgeFunc and
	 * DalvikNativeFunc; the former takes an argument superset (i.e. two
	 * extra args) which will be ignored. If necessary we can use
	 * insns==NULL to detect JNI bridge vs. internal native.
	 */
	DalvikBridgeFunc nativeFunc;
};

/*
 * Generic field header. We pass this around when we want a generic Field
 * pointer (e.g. for reflection stuff). Testing the accessFlags for
 * ACC_STATIC allows a proper up-cast.
 */
struct Field {
	ClassObject* clazz;//class in which the field is declared
	const char* name;
	const char* signature;//e.g. "I","[C","Landroid/os/Debug"
	u4 accessFlags;
//may have some code here
};

/*
 * Static field.
 */
struct StaticField {
	Field field;//Must be first item
	JValue value;//initially set from DEX for primitives
};

/*
 * Instance field
 */
struct InstField {
	Field field;//Must be fiest item

	/*
	 * This field indicates the byte offset from the beginning of the
	 * (Object *) to the actual instance data;e.g., byteOffset=0 is the same
	 * as the object pointer (bug!), and byteOffset==4 is 4 bytes farther.
	 */
	int byteOffset;
};

/*
 * Find a method within a class. The superclass is not searched.
 */
Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
		const char* methodName, const char* signature);
Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
		const char* methodName, const char* signature);

/*
 * Find a method within a class hierarchy
 */
Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
		const char* methodName, const char* signature);

/*
 * Get the source file associated with a method.
 */
const char* dvmGetMethodSourceFile(const Method* meth);

/*
 * Find a field within a class. The superclass is not searched.
 */
InstField* dvmFindInstanceField(const ClassObject* clazz,
		const char* fieldName, const char* signature);
StaticField* dvmFindStaticField(const ClassObject* clazz,
		const char* fieldName, const char* signature);

/*
 * Find a field and return the byte offset from the object pointer. Only
 * searches the specified class, not the superclass.
 *
 * Returns -1 on failure.
 */
INLINE int dvmFindFieldOffset(const ClassObject* clazz, const char* fieldName,
		const char* signature) {
	InstField* pField = dvmFindInstanceField(clazz, fieldName, signature);
	if (pField == NULL)
		return -1;
	else
		return pField->byteOffset;
}

/*
 * Helpers.
 */
INLINE bool dvmIsStaticMethod(const Method* method) {
	return (method->accessFlags & ACC_STATIC) != 0;
}

INLINE bool dvmIsFinalMethod(const Method* method) {
	return (method->accessFlags & ACC_FINAL) != 0;
}

INLINE bool dvmIsNativeMethod(const Method* method) {
	return (method->accessFlags & ACC_NATIVE) != 0;
}

INLINE bool dvmIsAbstractMethod(const Method* method) {
	return (method->accessFlags & ACC_ABSTRACT) != 0;
}

/*
 * Get whether the given method has associated bytecode. This is the
 * case for methods which are neither native nor abstract.
 */
INLINE bool dvmIsBytecodeMethod(const Method* method) {
	return (method->accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
}

INLINE bool dvmIsInterfaceClass(const ClassObject* clazz) {
	return (clazz->accessFlags & ACC_INTERFACE) != 0;
}

INLINE bool dvmIsAbstractClass(const ClassObject* clazz) {
	return (clazz->accessFlags & ACC_ABSTRACT) != 0;
}

INLINE bool dvmIsPublicClass(const ClassObject* clazz) {
	return (clazz->accessFlags & ACC_PUBLIC) != 0;
}

INLINE bool dvmIsFinalClass(const ClassObject* clazz) {
	return (clazz->accessFlags & ACC_FINAL) != 0;
}

//linked, here meaning prepared and resolved
INLINE bool dvmIsClassLinked(const ClassObject* clazz) {
	return clazz->status >= CLASS_RESOLVED;
}

//has class been verified?
INLINE bool dvmIsClassVerified(const ClassObject* clazz) {
	return clazz->status >= CLASS_VERIFIED;
}

/*
 * Get the associated code struct for a method. This returns NULL
 * for non-bytecode methods.
 */
INLINE const DexCode* dvmGetMethodCode(const Method* meth) {
	if (dvmIsBytecodeMethod(meth)) {
		/*
		 * The insns field for a bytecode method actually points at
		 * &(DexCode.insns), so we can subtract back to get at the
		 * DexCode in front.
		 */
		return (const DexCode*) (((const u1*) meth->insns)
				-offsetof(DexCode,insns));
	} else {
		return NULL;
	}
}

/*
 * Get the size of the insns associated with a method. This returns 0
 * for non-bytecode methods.
 */
INLINE u4 dvmGetMethodInsnsSize(const Method* meth) {
	const DexCode* pCode = dvmGetMethodCode(meth);
	return (pCode == NULL) ? 0 : pCode->insnsSize;
}
#endif /* OBJECT_H_ */
